#include <iostream>
#include <sys/types.h>
#ifdef WIN32
#pragma comment( lib, "ws2_32.lib" )
#include <windows.h>
#include <stdio.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
#include <string>
#include <cstring>
#include <sstream>
#include <fstream>
/*
* pop3_client.cpp
*
*  Created on: Oct 29, 2012
*      Author: simon
*/

using namespace std;

#ifdef WIN32 
//Win32 glue code
int read (int sd, char* buf, int len) {       
	return recv(sd, buf, len, 0);
}

int write (int sd, const char* buf, int len){
	return send(sd, buf, len, 0);
}

int startWinsock()
{
	WSADATA wsa;
	int wsacode =  WSAStartup(MAKEWORD(2,0),&wsa);	
	printf("WSA Startup %d\n" ,wsacode);
	return wsacode;
}

void close(int sd) {
	closesocket(sd);
	WSACleanup();
}

//Win32 starting Routines
void startWin32(){
	long rc;

	rc=startWinsock();

	if(rc!=0)
	{
		printf("Fehler: startWinsock, fehler code: %d\n",rc);
	}
	else
	{
		printf("Winsock gestartet!\n");
	}
}

void sleep(long duration_in_seconds){
	Sleep(duration_in_seconds * 1000);
}
#endif

//establishes the connection to the pop3-server
int connect_to_server()
{
	//open a internet stream over tcp
	int socket_descriptor = socket(AF_INET,SOCK_STREAM,0);

	//set up address
	struct sockaddr_in pop3_server;	
	pop3_server.sin_port=htons(110);
	pop3_server.sin_family = AF_INET;
	pop3_server.sin_addr.s_addr = inet_addr("137.248.123.123");


	int error = connect(socket_descriptor, (struct sockaddr *) &pop3_server, sizeof(pop3_server));
	if(error != 0){
		cout << "could not connect!";
#ifdef WIN32
		cout << WSAGetLastError();
		exit(1);
#endif
	}

	return socket_descriptor;
}

//reads from socket connection
string read_socket(int sd) {
	int cnt;
	int portion = 100;
	string input;
	do {
		char *buf = new char[portion];
		cnt = read(sd,(char*) buf, portion);
		input.append(buf, cnt);
	} while (cnt==portion);

	return input;
}

//writes to socket connection
void write_socket(int sd, string cmd)
{
	cmd.append("\r\n");
	char* buf = new char[cmd.size() +1];
	strcpy(buf,cmd.c_str());
	write(sd,buf,cmd.size());
}

//cares about the answer of the server
void process_answer(string cmd, int sd)
{
	string answer = read_socket(sd);
	if(answer.substr(0,3).compare("+OK")!=0)
		cout << cmd << "  was not successfull!" << endl;
}

//extracts the mail content out of the server answer
bool read_mail(int sd, int i, string *mail)
{
	//send request
	stringstream strstr; strstr << "RETR " << i;
	string cmd = strstr.str();
	write_socket(sd,cmd);
	//read answer
	string answer = read_socket(sd);

	//check answer
	if(answer.substr(0,4).compare("-ERR")==0)
		return false;
	else
	{
		//remove status message
		int pos = answer.find_first_of('\n');
		answer.erase(0,pos+1);
		//return mail and status
		*mail = answer;

		return true;
	}
}

//saves the mail to a file
void save_mail(string mail, int i)
{
	stringstream strstr; strstr << i << ".eml";
	string filename = strstr.str();
	ofstream f(filename.c_str());
	f.write(mail.c_str(),mail.size());
	f.close();
}

int main(int argc, char** argv)
{


	if(argc < 2)
	{
		cout << "Please add user as first argument and password as second!";
	}
	else
	{
#ifdef WIN32
		startWin32();
#endif
		string username(argv[1]);
		string passwd(argv[2]);

		//connect and remember socket desriptor
		int sd = connect_to_server();
		process_answer("Connection start ", sd);
		write_socket(sd,"USER "+username);
		process_answer("USER", sd);
		write_socket(sd,"PASS "+passwd);
		process_answer("PASS", sd);

		int n = 1;
		while(true){
			string mail;
			if(read_mail(sd, n, &mail))
			{
				cout << "fetch mail #" << n << endl;
				save_mail(mail,n);
			} else break;
			n++;
			sleep(1);
		}

		write_socket(sd,"QUIT");

		close(sd);
	}
	return 0;
}

